package org.sja.log2traffic.outputers;

import java.awt.Color;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Day;
import org.jfree.data.time.Hour;
import org.jfree.data.time.Minute;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.sja.log2traffic.IDateTimeFormatter;
import org.sja.log2traffic.IFileNameProvider;
import org.sja.log2traffic.IStatisticCalculator;
import org.sja.log2traffic.dataStructures.ChartPeriodEnum;
import org.sja.log2traffic.dataStructures.ConfigurationEntity;
import org.sja.log2traffic.dataStructures.CounterForDateAndResponseTimeEntity;
import org.sja.log2traffic.dataStructures.IOutputerSupport;
import org.sja.log2traffic.dataStructures.ProcessingStatusEntity;
import org.sja.log2traffic.dataStructures.ResultColumn;
import org.sja.log2traffic.dataStructures.ResultTable;
import org.sja.log2traffic.dataStructures.ResultValue;


public class MultipleAxisChartRenderer {

	public static final String FILE_NAME_SUFFIX = "traffic";
	private IDateTimeFormatter dateTimeFormatter;
	private IFileNameProvider fileNameProvider;
	private IStatisticCalculator statisticCalculator;

	public MultipleAxisChartRenderer(IDateTimeFormatter dateTimeFormatter, IFileNameProvider fileNameProvider, IStatisticCalculator statisticCalculator) {
		this.dateTimeFormatter = dateTimeFormatter;
		this.fileNameProvider = fileNameProvider;
		this.statisticCalculator = statisticCalculator;
	}

	public void renderChart(ConfigurationEntity configurationFromTo, ProcessingStatusEntity processingStatusEntity, IOutputerSupport data1, IOutputerSupport data2, String category) {
		ResultTable result1 = data1.getTable(configurationFromTo, category);
		ResultTable result2 = data2.getTable(configurationFromTo, category);
		List<ResultValue[]> list1 = result1.getValues();
		List<ResultValue[]> list2 = result2.getValues();
		ResultColumn[] columns1 = result1.getColumns();
		ResultColumn[] columns2 = result2.getColumns();

		TimeSeries dataset_1 = new TimeSeries(columns1[1].getColumnName());
		TimeSeries dataset_2 = new TimeSeries(columns1[2].getColumnName());
		TimeSeries dataset_5 = new TimeSeries(columns2[1].getColumnName());

		TimeSeriesCollection dataset_a = new TimeSeriesCollection();
		dataset_a.addSeries(dataset_1);
		TimeSeriesCollection dataset_b = new TimeSeriesCollection();
		dataset_b.addSeries(dataset_2);
		TimeSeriesCollection dataset_d = new TimeSeriesCollection();
		dataset_d.addSeries(dataset_5);

		for (ResultValue[] row : list1) {
			if (configurationFromTo.getChartPeriodEnum() == ChartPeriodEnum.HOUR) {
				dataset_1.add(new Hour(new Date(row[0].getValueAsLong())), row[1].getValueAsLong());
				dataset_2.add(new Hour(new Date(row[0].getValueAsLong())), row[2].getValueAsLong());
			} else {
				dataset_1.add(new Day(new Date(row[0].getValueAsLong())), row[1].getValueAsLong());
				dataset_2.add(new Day(new Date(row[0].getValueAsLong())), row[2].getValueAsLong());
			}
		}

		for (ResultValue[] row : list2) {
			if (row[1].getValueAsLong() > 0) {
				dataset_5.add(new Minute(new Date(row[0].getValueAsLong())), row[1].getValueAsLong());
			}
		}

		JFreeChart chart1 = ChartFactory.createTimeSeriesChart("Traffic", "Day of month", "amount", dataset_a, true, true, false);
		setPlotAtrribute(chart1.getXYPlot());
		JFreeChart chart2 = ChartFactory.createTimeSeriesChart("Traffic", "Day of month", "amount", dataset_b, true, true, false);
		setPlotAtrribute(chart2.getXYPlot());
		JFreeChart chart4 = ChartFactory.createScatterPlot("Traffic", "Day of month", "response time [ms]", dataset_d, PlotOrientation.VERTICAL, true, true, false);
		setPlotAtrribute(chart4.getXYPlot());

		CombinedDomainXYPlot plot = new CombinedDomainXYPlot(chart1.getXYPlot().getDomainAxis());
		plot.setGap(10.0);
		plot.add(chart1.getXYPlot(), 1);
		plot.add(chart2.getXYPlot(), 2);
		plot.add(chart4.getXYPlot(), 4);
		plot.setOrientation(PlotOrientation.VERTICAL);

		StringBuilder chartName = new StringBuilder();
		chartName.append('\'').append(category).append('\'');
		chartName.append(" from ").append(dateTimeFormatter.longToStringWithMinutes(configurationFromTo.getFrom()));
		chartName.append(" to ").append(dateTimeFormatter.longToStringWithMinutes(configurationFromTo.getTo()));

		JFreeChart chart = new JFreeChart(chartName.toString(), JFreeChart.DEFAULT_TITLE_FONT, plot, true);
		BufferedOutputStream output = null;
		configurationFromTo.getOutputDirectory().mkdirs();
		try {
			String ouputFileName = configurationFromTo.getOutputDirectory().getAbsolutePath() + '/' + fileNameProvider.provideFileName(configurationFromTo, category, FILE_NAME_SUFFIX)  + ".png";
			output = new BufferedOutputStream(new FileOutputStream(new File(ouputFileName)));
			ChartUtilities.writeChartAsPNG(output, chart, 1280, 768);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public void renderChart24Hours(ConfigurationEntity configurationFromTo, ProcessingStatusEntity processingStatusEntity, IOutputerSupport data, String category) {
		ResultTable result = data.getTable(configurationFromTo, category);
		List<ResultValue[]> list = result.getValues();
		ResultColumn[] columns = result.getColumns();

		TimeSeries dataset_1 = new TimeSeries(columns[1].getColumnName());
		TimeSeries dataset_2 = new TimeSeries(columns[2].getColumnName());

		TimeSeriesCollection dataset_a = new TimeSeriesCollection();
		dataset_a.addSeries(dataset_1);
		TimeSeriesCollection dataset_b = new TimeSeriesCollection();
		dataset_b.addSeries(dataset_2);

		for (ResultValue[] row : list) {
			if (row[1].getValueAsLong() > 0) {
				dataset_1.add(new Minute(new Date(row[0].getValueAsLong())), row[1].getValueAsLong());
			}
			dataset_2.add(new Minute(new Date(row[0].getValueAsLong())), row[2].getValueAsLong());
		}

		JFreeChart chart1 = ChartFactory.createTimeSeriesChart("Traffic", "24 hours", "amount", dataset_b, true, true, false);
		setPlotAtrribute(chart1.getXYPlot());
		JFreeChart chart2 = ChartFactory.createScatterPlot("Traffic", "24 hours", "response time [ms]", dataset_a, PlotOrientation.VERTICAL, true, true, false);
		setPlotAtrribute(chart2.getXYPlot());

		CombinedDomainXYPlot plot = new CombinedDomainXYPlot(chart1.getXYPlot().getDomainAxis());
		plot.setGap(10.0);
		plot.add(chart1.getXYPlot(), 1);
		plot.add(chart2.getXYPlot(), 2);
		plot.setOrientation(PlotOrientation.VERTICAL);

		StringBuilder chartName = new StringBuilder();
		chartName.append('\'').append(category).append('\'');
		chartName.append(" from ").append(dateTimeFormatter.longToStringWithMinutes(configurationFromTo.getFrom()));
		chartName.append(" to ").append(dateTimeFormatter.longToStringWithMinutes(configurationFromTo.getTo()));

		JFreeChart chart = new JFreeChart(chartName.toString(), JFreeChart.DEFAULT_TITLE_FONT, plot, true);
		BufferedOutputStream output = null;
		configurationFromTo.getOutputDirectory().mkdirs();
		try {
			String ouputFileName = configurationFromTo.getOutputDirectory().getAbsolutePath() + '/' + fileNameProvider.provideFileName(configurationFromTo, category, FILE_NAME_SUFFIX) + ".png";
			output = new BufferedOutputStream(new FileOutputStream(new File(ouputFileName)));
			ChartUtilities.writeChartAsPNG(output, chart, 1280, 1024);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public void renderChartProbability(ConfigurationEntity configurationFromTo, CounterForDateAndResponseTimeEntity counterForDateAndResponseTimeEntity) {
		String category = counterForDateAndResponseTimeEntity.getCategory();
		ResultTable result = statisticCalculator.getTableStatistic(counterForDateAndResponseTimeEntity);
		List<ResultValue[]> list = result.getValues();
		ResultColumn[] columns = result.getColumns();
		
		
		XYSeries seria_a = new XYSeries(columns[1].getColumnName());
		XYSeries seria_b = new XYSeries(columns[2].getColumnName());
		XYSeriesCollection dataset = new XYSeriesCollection();
		dataset.addSeries(seria_a);
		dataset.addSeries(seria_b);
		
		for (ResultValue[] row : list) {
			seria_a.add(row[0].getValueAsLong(), row[1].getValueAsDouble());
			seria_b.add(row[0].getValueAsLong(), row[2].getValueAsDouble());
		}

		JFreeChart chart = ChartFactory.createXYLineChart("Response time probability", "", "", dataset, PlotOrientation.VERTICAL, true, true, false);
		setPlotAtrributeWithDouble(chart.getXYPlot());

		StringBuilder chartName = new StringBuilder();
		chartName.append('\'').append(category).append('\'');
		chartName.append(" from ").append(dateTimeFormatter.longToStringWithMinutes(configurationFromTo.getFrom()));
		chartName.append(" to ").append(dateTimeFormatter.longToStringWithMinutes(configurationFromTo.getTo()));

		configurationFromTo.getOutputDirectory().mkdirs();
		BufferedOutputStream output = null;
		try {
			String ouputFileName = configurationFromTo.getOutputDirectory().getAbsolutePath() + '/' + fileNameProvider.provideFileName(configurationFromTo, category, "") + "_probability.png";
			output = new BufferedOutputStream(new FileOutputStream(new File(ouputFileName)));
			ChartUtilities.writeChartAsPNG(output, chart,  1280, 256);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
	
	
	private void setPlotAtrribute(XYPlot xyplot) {
		xyplot.setBackgroundPaint(Color.WHITE);
		xyplot.setDomainGridlinesVisible(true);
		xyplot.setRangeGridlinesVisible(true);
		xyplot.setDomainGridlinePaint(Color.BLACK);
		xyplot.setRangeGridlinePaint(Color.BLACK);
		NumberAxis rangeAxis = (NumberAxis) xyplot.getRangeAxis();
		rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
	}
	
	private void setPlotAtrributeWithDouble(XYPlot xyplot) {
		xyplot.setBackgroundPaint(Color.WHITE);
		xyplot.setDomainGridlinesVisible(true);
		xyplot.setRangeGridlinesVisible(true);
		xyplot.setDomainGridlinePaint(Color.BLACK);
		xyplot.setRangeGridlinePaint(Color.BLACK);
	}
	
}
